package xin.marcher.wind.process.demo;

import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.StringCodec;
import org.redisson.config.Config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import xin.marcher.wind.process.annoations.EnableProcessEngine;
import xin.marcher.wind.process.config.StringXmlProcessParser;
import xin.marcher.wind.process.model.ProcessContextFactory;
import xin.marcher.wind.process.processor.ProcessContext;
import xin.marcher.wind.process.refresh.ContinueProcessRefreshPolicy;
import xin.marcher.wind.process.store.DefaultProcessStateStore;
import xin.marcher.wind.process.store.ProcessStateStore;

import javax.annotation.Resource;

/**
 * @author marcher
 */
@Slf4j
@RestController
@SpringBootApplication
@EnableProcessEngine("process-demo.xml")
// 业务流程编排框架，直接把他的核心代码，去讲解一下，一边去进行画图
// spring boot整合以后，我们的框架在启动的时候，一般有两个进入点，@EnableProcessEngine -> 启用注解，会触发一些事情的执行
// spring boot -> 自动装配，框架体用了spring boot的自动装配的话，一般来说都会刚开始就直接去执行
public class Application {

    @Resource
    private ProcessContextFactory processContextFactory;

    @Bean
    public ProcessStateStore processStateStore() {
        return new DefaultProcessStateStore(redissonClient(), new ContinueProcessRefreshPolicy());
//        return new NoOpProcessStateStore();
    }


    private static RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379")
                .setConnectionMinimumIdleSize(10)
                .setConnectionPoolSize(100)
                .setIdleConnectionTimeout(600000)
                .setSubscriptionConnectionMinimumIdleSize(10)
                .setSubscriptionConnectionPoolSize(100)
                .setTimeout(30000);
        config.setCodec(new StringCodec());
        config.setThreads(5);
        config.setNettyThreads(5);
        return Redisson.create(config);
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }


    @GetMapping("/test1")
    public String test1() {
        // ProcessorDefinition是一套可运行的流程，包含的是流程的各个可运行的节点，这套东西只会有一套
        // ProcessContext，每次在运行一个流程的时候，相当于其实都是在运行一个流程实例，一次运行就是一个流程实例
        // 对于每个流程实例，都应该有自己当前这个流程实例的上下文，每次流程运行 -> 流程实例 -> ProcessContext上下文
        ProcessContext process1 = processContextFactory.getContext("process1");
        process1.set("nextId", "node4"); // 在流程实例上下文里，是可以放置一些本次流程实例运行需要的一些变量数据
        // 在你的本次流程运行过程中，各个流程节点之间如果需要传递数据的话，都是通过你本次流程实例的ProcessContext上下文来传递数据的
        // 也可以在流程实例开始运行之前，就投放进去一些流程实例运行可能需要的数据
        process1.start();

        return "true";
    }

    @GetMapping("/test2")
    public String test2() throws Exception {
        ProcessContext process1 = processContextFactory.getContext("process1");
        log.info("before refresh process......");
        process1.set("id", "process1");
        process1.start();
        String dynamicXmlConfig = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<process-context xmlns=\"http://www.w3school.com.cn\"\n" +
                "                 xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
                "                 xsi:schemaLocation=\"http://www.w3school.com.cn process-engine.xsd\">\n" +
                "    <process name=\"process1\">\n" +
                "        <node name=\"node1\" class=\"xin.marcher.wind.process.demo.processor.StandardProcessorDemo\" next=\"node2\" begin=\"true\"/>\n" +
                "        <node name=\"node2\" class=\"xin.marcher.wind.process.demo.processor.StandardProcessorDemo\"/>\n" +
                "    </process>\n" +
                "\n" +
                "</process-context>";
        StringXmlProcessParser stringXmlProcessParser = new StringXmlProcessParser(dynamicXmlConfig);
        processContextFactory.refresh(stringXmlProcessParser.parse());
        process1 = processContextFactory.getContext("process1");
        log.info("after refresh process......");
        process1.set("id", "process1");
        process1.start();
        return "true";
    }
}
